HDU 5755 Gambler Bo(高斯消元)

题意:

$给定N\times M的矩阵,N,M\le 30,每个格子里的数A_{ij}\in [0, 3)$
$每次可以按一个格子,使得这个格子+2,上下左右4个格子+1,数加完后会模3$
$输出1个可以使得所有格子都变成0的操作,保证数据有解$

分析:

$对N\times M个格子建立方程,每个格子含有5个变元$
$高斯消元解方程,打印解即可$
$时间复杂度O((NM)^3)$

代码:

//
//  Created by TaoSama on 2016-07-26
//  Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 30 * 30 + 10, INF = 0x3f3f3f3f, MOD = 3;

int n, m, val[N];
int a[N][N], ans[N];
bool isFreeX[N];

inline int inv(int x) {return x;}

void getAns(int n, int m, int r) {
    for(int i = r - 1; ~i; --i) {
        for(int j = 0; j < m; ++j) {
            if(!a[i][j]) continue;
            ans[j] = a[i][m];
            for(int k = j + 1; k < m; ++k) {
                ans[j] -= a[i][k] * ans[k];
                ans[j] %= MOD;
                if(ans[j] < 0) ans[j] += MOD;
            }
            ans[j] = ans[j] * inv(a[i][j]) % MOD;
            break;
        }
    }
}

int gauss(int n, int m) {
    for(int i = 0; i < m; ++i) isFreeX[i] = false;
    int r = 0, c = 0;
    for(; r < n && c < m; ++r, ++c) {
        int maxR = r;       //row transform
        for(int i = r + 1; i < n; ++i)
            if(abs(a[i][c]) > abs(a[maxR][c])) maxR = i;
        if(maxR != r) swap(a[maxR], a[r]);

        if(!a[r][c]) { --r; isFreeX[c] = true; continue;}

        //eliminate coefficient
        for(int i = r + 1; i < n; ++i) {
            if(a[i][c]) {
                int delta = a[i][c] * inv(a[r][c]);
                for(int j = c; j <= m; ++j) {
                    a[i][j] -= delta * a[r][j];
                    a[i][j] %= MOD;
                    if(a[i][j] < 0) a[i][j] += MOD;
                }
            }
        }
    }
    for(int i = r; i < n; i++) if(a[i][m]) return -1;

    getAns(n, m, r);

    //at last, r is rank, m - r is the number of freeX
    return r;
}

int main() {
#ifdef LOCAL
    freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);
    clock_t _ = clock();

    int t; scanf("%d", &t);
    while(t--) {
        scanf("%d%d", &n, &m);
        memset(a, 0, sizeof a);
        for(int i = 0; i < n * m; ++i) {
            scanf("%d", val + i);
            int x = i / m, y = i % m;
            a[i][i] = 2;
            static int d[][2] = { -1, 0, 0, -1, 1, 0, 0, 1};
            for(int j = 0; j < 4; ++j) {
                int nx = x + d[j][0], ny = y + d[j][1];
                if(nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
                a[i][nx * m + ny] = 1;
            }
            a[i][n * m] = -val[i] + MOD;
        }

        gauss(n * m, n * m);

        vector<pair<int, int> > v;
        for(int i = 0; i < n * m; ++i) {
            int x = i / m, y = i % m;
//            printf("%d, %d : %d\n", x, y, ans[i]);
            while(ans[i]--) {
                v.push_back({x + 1, y + 1});
//                static int d[][2] = { -1, 0, 0, -1, 1, 0, 0, 1};
//                val[i] = (val[i] + 2) % MOD;
//                for(int j = 0; j < 4; ++j) {
//                    int nx = x + d[j][0], ny = y + d[j][1];
//                    if(nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
//                    val[nx * m + ny] ++;
//                    val[nx * m + ny] %= MOD;
//                }
            }
        }
//        if(count(val, val + n * m, 0) != n * m) puts("WA");
//        else puts("AC");

        printf("%d\n", v.size());
        for(auto& p : v) printf("%d %d\n", p.first, p.second);
    }

#ifdef LOCAL
    printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);
#endif
    return 0;
}